package jp.seraph.same.view;

import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ComponentInputMap;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import net.sf.json.JsonConfig;

import jp.seraph.same.controller.AgentController;
import jp.seraph.same.controller.MotionController;
import jp.seraph.same.controller.PoseController;
import jp.seraph.same.model.AgentModel;
import jp.seraph.same.model.MotionCollectionModel;
import jp.seraph.same.model.PoseCollectionModel;

/**
 * モーションエディタの最上位に表示されるパネル（フォーム）です。
 */
public class MainPanel extends JFrame {
    public MainPanel(AgentController aController, AgentModel aAgentModel, PoseCollectionModel aPoseModel, PoseController aPoseController, MotionCollectionModel aMotionModel, MotionController aMotionController) {
        this(aController, aAgentModel, new PosePanel(aPoseModel, aPoseController), new MotionPanel(aMotionModel, aPoseModel, aMotionController));
    }

    public MainPanel(AgentController aController, AgentModel aAgentModel, PosePanel aPosePanel, MotionPanel aMotionPanel) {
        mController = aController;
        mPosePanel = aPosePanel;
        mMotionPanel = aMotionPanel;
        mAgentModel = aAgentModel;
        mBeamButton = new JButton("beam");
        mBeamCheck = new JCheckBox("連続");
        mXField = new JTextField("0.0");
        mYField = new JTextField("0.0");
        mZField = new JTextField("0.0");

        mAgentCanvas = new AgentCanvas(aAgentModel);

        mTabPanel = new JTabbedPane();

        initializeComponents();

        mBeamButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                beamButtonClicked();
            }
        });

        mBeamCheck.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ev) {
                if (mBeamCheck.isSelected()) {
                    double tX;
                    double tY;
                    double tZ;

                    try {
                        tX = Double.parseDouble(mXField.getText());
                        tY = Double.parseDouble(mYField.getText());
                        tZ = Double.parseDouble(mZField.getText());
                    } catch (NumberFormatException e) {
                        JOptionPane.showMessageDialog(MainPanel.this, "フィールドのフォーマットが不正です．doubleにparseできる文字列を入力してください．");
                        return;
                    }

                    mController.startPermanentBeam(tX, tY, tZ);
                } else {
                    mController.endPermanentBeam();
                }
            }
        });

        mXField.getDocument().addDocumentListener(new FieldChangeListener(mXField));
        mYField.getDocument().addDocumentListener(new FieldChangeListener(mYField));
        mZField.getDocument().addDocumentListener(new FieldChangeListener(mZField));

        mTabPanel.addChangeListener(new ChangeListener() {

            public void stateChanged(ChangeEvent e) {
                tabPanelChanged();
            }
        });

        BeamAction tAction = new BeamAction();

        InputMap tInputMap = new ComponentInputMap(mTabPanel);
        ActionMap tActionMap = mTabPanel.getActionMap();

        tInputMap.put(KeyStroke.getKeyStroke('b'), tAction);
        tActionMap.put(tAction, tAction);

        mTabPanel.setInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW, tInputMap);
        mTabPanel.setActionMap(tActionMap);
    }

    private class BeamAction extends AbstractAction{

        /**
         *
         * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
         */
        public void actionPerformed(ActionEvent aE) {
            beamButtonClicked();
        }
    }

    private void initializeComponents() {
        mTabPanel.addTab("Pose", mPosePanel);
        mTabPanel.addTab("Motion", mMotionPanel);
        mTabPanel.addTab("Etc", createEtcComponent());

        this.add(mTabPanel);
    }

    private Component createEtcComponent() {
        JPanel tFlow = new JPanel();
        tFlow.setLayout(new FlowLayout());
        tFlow.add(mXField);
        tFlow.add(mYField);
        tFlow.add(mZField);
        tFlow.add(mBeamButton);
        tFlow.add(mBeamCheck);

        Box tBox = new Box(BoxLayout.Y_AXIS);
        tBox.add(tFlow);
        tBox.add(mAgentCanvas);

        return tBox;
    }

    private void beamButtonClicked() {
        double tX;
        double tY;
        double tZ;

        try {
            tX = Double.parseDouble(mXField.getText());
            tY = Double.parseDouble(mYField.getText());
            tZ = Double.parseDouble(mZField.getText());
        } catch (NumberFormatException e) {
            JOptionPane.showMessageDialog(this, "フィールドのフォーマットが不正です．doubleにparseできる文字列を入力してください．");
            return;
        }

        mController.beam(tX, tY, tZ);
    }

    private void tabPanelChanged() {
        Component tComponent = mTabPanel.getSelectedComponent();
        if (tComponent == null)
            return;

        if (tComponent.equals(mPosePanel)) {
            // PosePanelはrefreshする必要が無い．
        } else if (tComponent.equals(mMotionPanel)) {
            mMotionPanel.refresh();
        }
    }

    private AgentController mController;

    private PosePanel mPosePanel;

    private MotionPanel mMotionPanel;

    private JButton mBeamButton;

    private JTextField mXField;

    private JTextField mYField;

    private JTextField mZField;

    private JTabbedPane mTabPanel;

    private AgentCanvas mAgentCanvas;

    private JCheckBox mBeamCheck;

    AgentModel mAgentModel;

    private static final long serialVersionUID = 10L;

    private class FieldChangeListener implements DocumentListener {
        public FieldChangeListener(JTextField aField) {
            mField = aField;
        }

        private JTextField mField;

        /**
         *
         * @see javax.swing.event.DocumentListener#changedUpdate(javax.swing.event.DocumentEvent)
         */

        public void changedUpdate(DocumentEvent aE) {
        }

        /**
         *
         * @see javax.swing.event.DocumentListener#insertUpdate(javax.swing.event.DocumentEvent)
         */

        public void insertUpdate(DocumentEvent aE) {
            mField.setSize(mField.getPreferredSize());
            mField.getParent().validate();
        }

        /**
         *
         * @see javax.swing.event.DocumentListener#removeUpdate(javax.swing.event.DocumentEvent)
         */

        public void removeUpdate(DocumentEvent aE) {
            mField.setSize(mField.getPreferredSize());
            mField.getParent().validate();
        }

    }
}
